.global _start

_start:
	/* ARM Contex-A7 内核有8个中断向量，中断向量表放在程序的起始位置 */
	/* I.MX6U Contex-A7中断向量表 */
	ldr pc, =Reset_Handler				/* 复位中断服务函数 */
	ldr pc, =Undefined_Handler			/* 未定义指令中断服务函数 */
	ldr pc, =SVC_Handler				/* SVC中断服务函数 */
	ldr pc, =PerfAbort_Handler			/* 指令预取中止中断服务函数 */
	ldr pc, =DataAbort_Handler			/* 数据中止中断服务函数 */
	ldr pc, =NotUsed_Handler			/* 未使用中断服务函数 */
	ldr pc, =IRQ_Handler				/* IRQ中断服务函数 */
	ldr pc, =FIQ_Handler				/* FIQ中断服务函数 */


/* 复位中断服务函数 */
Reset_Handler:
	//ldr r0, =Reset_Handler
	//bx r0;
	
	/*关闭外部IRQ中断*/
	cpsid i							/*关闭IRQ中断的汇编指令*/

	/*关闭I/D Cache, MMU, 分支预测，内存对齐检查*/
	/*SCTLR: System Control Register*/
	MRC p15, 0, r0, c1, c0, 0  		/* Read System Control Register */
	bic r0, r0, #(1<<0)		  		/* bit[0]关闭MMU */
	bic r0, r0, #(1<<1)		  		/* bit[1]关闭内存对齐检查 */
	bic r0, r0, #(1<<2)		  		/* bit[2]关闭D-Cache */
	bic r0, r0, #(1<<11)	  		/* bit[11]关闭分支预测 */
	bic r0, r0, #(1<<12)	  		/* bit[12]关闭I-Cache */
	MCR p15, 0, r0, c1, c0, 0  		/* Write System Control Register */


	/*设置中断向量表基地址 VBAR 寄存器*/
	/*VBAR:Vector Base Address Register*/
	//MRC p15,0,r0,c12,c0,0			/* Read Vector Base Address Register */
	ldr r0, =0x87800000				/* 设置中断向量表基地址为0x87800000 */

	dsb
	isb
	MCR p15, 0, r0, c12, c0, 0		/* Write Vector Base Address Register */
	dsb
	isb

	/* 调用我写的汇编函数 bss_clean, 在bss_clean函数中清零.bss段 */
	bl clean_bss


	/*设置SYS,IRQ,SVC模式的SP(R14寄存器)指针*/
	/* 设置 IRQ mode SP */
	mrs r0, cpsr					@read cpsr
	bic r0, #0x1f					@clear cpsr M[4:0]
	orr r0, #0x12					@set cpsr M[4:0]=0x12, it is IRQ mode
	msr cpsr, r0					@write cpsr
	ldr sp, =0x80600000				/* 设置 IRQ SP */
	

	/* 设置 SYS mode SP */
	mrs r0, cpsr					@read cpsr
	bic r0, #0x1f					@clear cpsr M[4:0]
	orr r0, #0x1f					@set cpsr M[4:0]=0x1f, it is SYS mode
	msr cpsr, r0					@write cpsr
	ldr sp, =0x80400000				/* 设置 SYS SP */

	/* 设置 SVC mode SP */
	mrs r0, cpsr					@read cpsr
	bic r0, #0x1f					@clear cpsr M[4:0]
	orr r0, #0x13					@set cpsr M[4:0]=0x13, it is svc mode
	msr cpsr, r0					@write cpsr
	ldr sp, =0x80200000				/* 设置 SVC SP */

	/* 打开外部IRQ中断开关 */
	cpsie i

	/*跳转到C函数*/
	b main


/* 未定义指令中断服务函数 */
Undefined_Handler:
	ldr r0, =Undefined_Handler
	bx r0;

/* SVC中断服务函数 */
SVC_Handler:
	ldr r0, =SVC_Handler
	bx r0;

/* 指令预取中止中断服务函数 */
PerfAbort_Handler:
	ldr r0, =PerfAbort_Handler
	bx r0;

/* 数据中止中断服务函数 */
DataAbort_Handler:
	ldr r0, =DataAbort_Handler
	bx r0;

/* 未使用中断服务函数 */
NotUsed_Handler:
	ldr r0, =NotUsed_Handler
	bx r0;

/* IRQ中断服务函数 */
IRQ_Handler:
	@ ldr r0, =IRQ_Handler
	@ bx r0;

	push {lr}					/* lr_irq入栈保存，保存到IRQ栈 */
	push {r0-r3, r12}			/* r0-r3, r12入栈保存，保存到IRQ栈  */
	mrs r0, spsr				/* read cpsr_irq */
	push {r0}					/* spsr_irq 入栈保存，保存到IRQ栈 */
	
	mrc p15, 4, r1, c15, c0, 0	/* 读取cp15协处理器的c15到r1中，也就是 GICC_CBAR 
								 * 的GIC内存映射区的起始基地址 */
	add r1, r1, #0x2000			/* GIC的CPU接口端寄存器基地址 */
	ldr r0, [r1, #0xc]			/* GICC_IAR 寄存器读取到r0，GICC_IAR中可以读取到中断ID号 */
	push {r0,r1}				/* r0,r1入栈保存，保存到IRQ栈，此时r1=GIC内存映射区的基地址,
								 * r0=GICC_IAR */
	
	cps #0x13					/* 进入到 SVC 模式 */
	push {lr}					/* lr_svc入栈保存，保存到SVC栈。因为接下来bl指令会修改lr_svc，
								 * 所以这里在bl指令之前先将 lr_svc 入栈 */
	ldr r2, =system_irqhandler	
	blx r2						/* 调用C函数 system_irqhandler， 通过r0第一个参数给C函数 */
	pop {lr}					/* lr_svc 出栈 */
	cps #0x12					/* 返回到 IRQ 模式*/


	pop {r0,r1}					/* IRQ出栈r0,r1，因为上面在进入SVC模式之前push了r0,r1，所以这里要出栈r0,r1*/
	@中断处理完成必须写 GICC_EOIR（End Of Interrupt Register）寄存器通知GIC控制器中断处理完成
	str r0, [r1, #0x10]			/* r0中保存的是GICC_IAR，r1中保存GIC的CPU接口端寄存器起始基地址，
								 * r1+0x10 是寄存器GICC_EOIR， 写r0到r1+0x10就是 GICC_EOIR=r0，
								 * 也就是写中断ID到GICC_EOIR寄存器 
								 */
	
	@ ldr r0, =30
	@ ldr r2, =beep_times
	@ blx r2

	pop {r0}					/* IRQ栈 cpsr 出栈到r0 */
	msr spsr_cxsf, r0 			/* 恢复cpsr寄存器 */
	pop {r0-r3, r12}			/* IRQ栈 r0-r3,r12 出栈，恢复r0-r3,r12 */
	pop {lr}					/* IRQ栈 lr 出栈，恢复lr */
	@sub pc, lr, #4				/* PC=lr-4 返回到被中断的指令继续执行 */
	subs pc, lr, #4				/* PC=lr-4 返回到被中断的指令继续执行 */
	


/* FIQ中断服务函数 */
FIQ_Handler:
	ldr r0, =FIQ_Handler
	bx r0;



clean_bss:
	/* clear .bss to zero */
	ldr r0, _bss_start
	ldr r1, _bss_end
	mov r2, #0
bss_loop:
	stmia r0!, {r2}
	cmp r0, r1		@compare r0, r1
	ble bss_loop	@jump to bss_loop if r0 <= r1
	//ldr pc, lr
	bx lr
	
	
.global _bss_start
_bss_start:
	.word __bss_start

.global _bss_end
_bss_end:
	.word __bss_end

//